package com.shujia.connectionPool;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;

public class ConnectionPoolImpl implements ConnectionPool {

    // 未被使用的连接
    ArrayList<PoolElem> noUsedConnectionPool = new ArrayList<PoolElem>();

    // 使用的连接
    ArrayList<PoolElem> usedConnectionPool = new ArrayList<PoolElem>();

    ConnectionPoolConfig connectionPollConfig;

    // 读取到了所有的配置信息了

    public ConnectionPoolImpl(ConnectionPoolConfig connectionPollConfig) {
        this.connectionPollConfig =connectionPollConfig;
        // 获取一开始 连接池初始化的连接数量
        int initNum = connectionPollConfig.getInitNum();
        System.out.println("连接池正在创建...需要实例化"+initNum+"个连接");
        // 循环创建对应的连接
        for (int i = 0; i < initNum; i++) {
            PoolElem poolElem = createOneConnection(connectionPollConfig);
            noUsedConnectionPool.add(poolElem);
            System.out.println("第"+(i+1)+"个连接创建成功...");
        }
    }

    @Override
    public synchronized PoolElem  createOneConnection(ConnectionPoolConfig connectionPollConfig) {
        PoolElem poolElem = null;
        try {
            Class.forName(connectionPollConfig.driver);

            Connection connection = DriverManager.getConnection(
                    connectionPollConfig.getUrl()
                    , connectionPollConfig.getUser()
                    , connectionPollConfig.getPasswd()
            );

            poolElem = new PoolElem(connection, new Date());

        } catch (ClassNotFoundException | SQLException e) {
            throw new RuntimeException(e);
        }
        return poolElem;
    }

    @Override
    public synchronized Connection getConnection() {
        PoolElem poolElem = null;
        if (noUsedConnectionPool.size() > 0) {
            // 从未使用的连接池将连接移动至使用的连接池中
            poolElem = noUsedConnectionPool.remove(0);

            usedConnectionPool.add(poolElem);
            System.out.println(Thread.currentThread().getName()+"获取到一个连接");
            System.out.println("当前未使用的连接数量："+noUsedConnectionPool.size()+" 正在使用的连接数量："+usedConnectionPool.size());
        }else{
            // 如果连接池数量没有了，那么怎么办？
            // 1.什么情况下可以创建？
            int maxNum = connectionPollConfig.getMaxNum();
            if (usedConnectionPool.size() < 10){
                poolElem = createOneConnection(connectionPollConfig);
                usedConnectionPool.add(poolElem);
                System.out.println("当前连接不足，并且没有达到上限，那么可以创建一个新的连接，并将其添加到正在使用的连接池中...");
                System.out.println("当前未使用的连接数量："+noUsedConnectionPool.size()+" 正在使用的连接数量："+usedConnectionPool.size());
            }else {
                // 2.什么情况下需要等待？
                try {
                    System.out.println("当前连接不足，并且达到上限了...，需要对获取的当前线程进行等待.."+Thread.currentThread().getName());
                    wait();
                    return getConnection();  // 当等待后，被唤醒可以继续执行代码，那么需要再调用自身获取对用的连接
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }

        }

        return poolElem.getConnection();
    }

    @Override
    public synchronized void releaseConnection(Connection connection) {
        // 获取到一个连接后，需要将该连接从 使用的连接池中 移动至 未使用的连接池中

        // 步骤：需要遍历使用的集合中每个PoolElem对象 并获取Connection 再去对比传入的Connection对象
        for (PoolElem poolElem : usedConnectionPool) {
            if (poolElem.getConnection() == connection) {
                // 先移除
                usedConnectionPool.remove(poolElem);

                // 添加
                noUsedConnectionPool.add(poolElem);
                System.out.println(Thread.currentThread().getName()+"：当前线程释放了一个连接:"+connection);
                System.out.println("当前未使用的连接数量："+noUsedConnectionPool.size()+" 正在使用的连接数量："+usedConnectionPool.size());
                notify(); // 去唤醒一个没有获取到连接的线程

            }
        }

    }
}
